#ifndef OBJECT_H
#define OBJECT_H

#include "var.h"
#include "action.h"

#include "tinyxml.h"

#include <boost/python.hpp>
#include <string>
#include <map>

///sdse_lin_includeDir /usr/include/python2.5
///sdse_lib python2.5
///sdse_lib boost_python
///sdse_lib boost_date_time
///sdse_lib enet

namespace sde {
    class Object;
    
    typedef std::map<std::string, Object*> StringObjectMap;
    
    typedef boost::function<void(Var)> SetVarFunction;
    typedef std::list<SetVarFunction> SetVarFunctionList;
    typedef std::map<std::string, SetVarFunctionList> SetVarFunctionMap;
    
    typedef boost::function<Var(VarMap)> RpcFunction;
    typedef std::map<std::string, RpcFunction> RpcFunctionMap;
    
    struct RpcDeferral {
        std::string objectName, cmd;
        
        Var operator()();
    };

    class Object {
    private:
        PythonObjectListMap pythonSubscriptions, pythonSetVarFunctions;
        PythonObjectMap pythonRpcFunctions;
    
        VarMap vars;
        StringList requestedVars;
    
        std::string makeName(std::string desiredName);
        
        Action* actionFactory(std::string actionType, std::string actionName);
        
        void loadVar(TiXmlElement* element);
        void loadAction(TiXmlElement* element);
        void loadScript(TiXmlElement* element);
        void loadInclude(TiXmlElement* element);
        
        static boost::python::object PythonObject, mainNamespace, hasAttr;
        
        SetVarFunctionMap setVarFunctions;
        
        void doStopAction(Action* action);
        
        RpcFunctionMap rpcFunctions;
        bool hasCRpc(std::string cmd);
        bool hasPythonRpc(std::string cmd);
        
    public:
        static boost::python::object glob, osPath;
    
        void subscribeRpc(std::string cmd, RpcFunction function);
        Var doCallRpc(std::string cmd, VarMap args);
        RpcDeferral deferRpc(std::string cmd, VarMap args);
        Var finishRpc(std::string cmd);
        Var callRpc(std::string cmd, VarMap args);
        bool hasRpc(std::string cmd);
        static bool rpcIsLocal(std::string objectName, std::string cmd);
    
        void subscribeSetVar(std::string varName, SetVarFunction function);
    
        static boost::python::object PythonVector2, PythonVector3, PythonQuaternion;
    
        StringActionMap actions;
        
        std::string name;
    
        static StringObjectMap allObjects;
    
        Object(std::string desiredName, bool fromServer = false);
        ~Object();
        
        std::string runAction(std::string actionType, std::string actionName);
        void doRunAction(std::string actionType, std::string actionName);
        bool hasAction(std::string actionName);
        void stopAllActions();
        bool stopAction(std::string actionName);
        Action* getAction(std::string actionName);
        static Action* searchForAction(std::string actionName);
        Action* getFirstActionOfArchetype(std::string type);
        
        void log(const char* fmt, ...);
    
        static Object* getObject(std::string objectName);
        static bool deleteObject(std::string objectName, bool tellServer = true);
        static bool hasObject(std::string objectName);
        
        static bool shutdown;
        static void runSimulation(int argc, char** argv);
        static void shutdownSimulation();
        static void deleteAllObjects(bool tellServer = false);
        
        bool hasVar(std::string varName);
        Var getVar(std::string varName, Var def = Var());
        void setVar(std::string varName, Var val, bool tellServer = true);
        void distSetVar(std::string varName, Var val);
        Var defaultVar(std::string varName, Var val);
        void requestVar(std::string varName);
        void updateVars(VarMap vals, bool tellServer = true);
        
        static float getTime();
        
        void loadFile(std::string filename);
        void load(TiXmlElement* element);
        
        void runScript(std::string filename);
        static void initPython();
        
        void receiveForPython(VarMap args);
        
        static bool pyHasVar(std::string objectName, std::string varName);
        static void pySetVar(std::string objectName, std::string varName, boost::python::object val);
        static boost::python::object pyGetVar(std::string objectName, std::string varName);
        
        static boost::python::object pyRunAction(std::string objectName, std::string actionType, std::string actionName);
        static bool pyStopAction(std::string objectName, std::string actionName);
        static void pyStopAllActions(std::string objectName);
        
        static void pyLoad(std::string objectName, std::string filename);
        
        static std::string pyMakeObject(std::string objectName);
        static bool pyDeleteObject(std::string objectName);
        
        static void pyLog(std::string objectName, std::string msg);
        
        static void pyRunScript(std::string objectName, std::string scriptName);
        
        static void pyRequestRpc(std::string objectName, std::string cmd, boost::python::object args);
        static boost::python::object pyFinishRpc(std::string objectName, std::string cmd);
        
        static void pyPublish(std::string cmd, boost::python::object args);
        static boost::python::object pyGetObjectNames();
    };
}

#endif
